#include "game.h"
#include <stdint.h>

static node_t *walls_list;
static uint32_t walls_cur;

uint8_t q_map[HEIGHT_AREA][WIDTH_AREA] = {0};

extern FILE* log_file;

int8_t check_wall(uint8_t x, uint8_t y)
{
    uint8_t n_neigh = 0;

    node_t *iter = walls_list->next;
    uint8_t iter_x, iter_y;

    if (x < 1 || y < 1 || x > (WIDTH_AREA - 2) || y > (HEIGHT_AREA - 2))
        return -2;

    while (iter != NULL)
    {
        iter_x = ((wall_t*)(iter->data))->crd.x;
        iter_y = ((wall_t*)(iter->data))->crd.y;

        if (iter_x == x && iter_y == y)
            return -1;

        if (iter_x == (x + 1) && iter_y == y)
        {
            n_neigh += 1;
            if (((wall_t*)(iter->data))->n_neigh + 1 > 2)
                return -1;        
        }
        else if (iter_x == (x - 1) && iter_y == y)
        {
            n_neigh += 1;
            if (((wall_t*)(iter->data))->n_neigh + 1 > 2)
                return -1;        
        }
        else if (iter_x == x && iter_y == (y + 1))
        {
            n_neigh += 1;
            if (((wall_t*)(iter->data))->n_neigh + 1 > 2)
                return -1;       
        }
        else if (iter_x == x && iter_y == (y - 1))
        {
            n_neigh += 1;
            if (((wall_t*)(iter->data))->n_neigh + 1 > 2)
                return -1;       
        }
        else if (iter_x == (x - 1) && iter_y == (y - 1))
        {
            n_neigh += 1;
            if (((wall_t*)(iter->data))->n_neigh + 1 > 2)
                return -1;        
        }
        else if (iter_x == (x - 1) && iter_y == (y + 1))
        {
            n_neigh += 1;
            if (((wall_t*)(iter->data))->n_neigh + 1 > 2)
                return -1;        
        }
        else if (iter_x == (x + 1) && iter_y == (y - 1))
        {
            n_neigh += 1;
            if (((wall_t*)(iter->data))->n_neigh + 1 > 2)
                return -1;        
        }
        else if (iter_x == (x + 1) && iter_y == (y + 1))
        {
            n_neigh += 1;
            if (((wall_t*)(iter->data))->n_neigh + 1 > 2)
                return -1;
        }
        
        if (n_neigh > 2)
            return -1;

        iter = iter->next;
    }


    iter = walls_list->next;
    while (iter != NULL)
    {
        iter_x = ((wall_t*)(iter->data))->crd.x;
        iter_y = ((wall_t*)(iter->data))->crd.y;

        if (iter_x == (x + 1) && iter_y == y)
            ((wall_t*)(iter->data))->n_neigh += 1;
        else if (iter_x == (x - 1) && iter_y == y)
            ((wall_t*)(iter->data))->n_neigh += 1;
        else if (iter_x == x && iter_y == (y + 1))
            ((wall_t*)(iter->data))->n_neigh += 1;
        else if (iter_x == x && iter_y == (y - 1))
            ((wall_t*)(iter->data))->n_neigh += 1;
        else if (iter_x == (x - 1) && iter_y == (y - 1))
            ((wall_t*)(iter->data))->n_neigh += 1;
        else if (iter_x == (x - 1) && iter_y == (y + 1))
            ((wall_t*)(iter->data))->n_neigh += 1;
        else if (iter_x == (x + 1) && iter_y == (y - 1))
            ((wall_t*)(iter->data))->n_neigh += 1;
        else if (iter_x == (x + 1) && iter_y == (y + 1))
            ((wall_t*)(iter->data))->n_neigh += 1;
        
        iter = iter->next;
    }


    return n_neigh;
}


void gen_walls()
{
    wall_t *new_wall;
    node_t *iter;
    node_t *end;

    uint8_t tries = TRIES;
    uint8_t new_wall_x, new_wall_y;
    int8_t neigh;

    time_t seed = time(NULL);

    srand(seed);

    fprintf(log_file, "[SERVER] seed: %lu\n", seed);

    new_wall = malloc(sizeof(wall_t));

    new_wall->crd.x = rand() % (WIDTH_AREA - 3) + 1;
    new_wall->crd.y = rand() % (HEIGHT_AREA - 3) + 1;
    new_wall->n_neigh = 0;
    fprintf(log_file, "[SERVER] Gen wall x: %d, y: %d, neih: 0\n", new_wall->crd.x, new_wall->crd.y);

    init_list(&walls_list);
    insert_node(walls_list, new_wall);

    iter = walls_list->next;
    walls_cur = 1;
    for (int i = 0; i < ANCHORS; ++i) 
    {
        new_wall_x = rand() % (WIDTH_AREA - 3) + 1;
        new_wall_y = rand() % (HEIGHT_AREA - 3) + 1;
        if ((neigh = check_wall(new_wall_x, new_wall_y)) >= 0)
        {
            new_wall = malloc(sizeof(wall_t));

            new_wall->crd.x = new_wall_x;
            new_wall->crd.y = new_wall_y;
            new_wall->n_neigh = neigh;
            fprintf(log_file, "[SERVER] Gen wall x: %d, y: %d, neih: 0\n", new_wall_x, new_wall_y);

            iter = insert_node(iter, new_wall);
        }
        else
            i -= 1;
    }

    end = iter;
    walls_cur = ANCHORS + 1;
    iter = walls_list->next;
    while (walls_cur < MAX_WALLS)
    {
        new_wall_x = ((wall_t *)(iter->data))->crd.x + (rand() % 3 - 1);
        new_wall_y = ((wall_t *)(iter->data))->crd.y + (rand() % 3 - 1);

        if ((neigh = check_wall(new_wall_x, new_wall_y)) >= 0)
        {
            new_wall = malloc(sizeof(wall_t));

            new_wall->crd.x = new_wall_x;
            new_wall->crd.y = new_wall_y;
            new_wall->n_neigh = neigh;
            fprintf(log_file, "[SERVER] Gen wall x: %d, y: %d, neigh: %d\n", new_wall_x, new_wall_y, neigh);

            end = insert_node(end, new_wall);

            walls_cur += 1;
        }
        else if (neigh == -2)
            continue;
        else if (neigh == -1)
            if ((tries--) == 0)
                break;

        if (iter->next == NULL)
            iter = walls_list->next;
        else
            iter = iter->next;
    }
}


crd_t create_qmap()
{
    node_t *iter;

    crd_t tmp;

    gen_walls();

    iter = walls_list->next;
    while (iter != NULL)
    {
        q_map[((wall_t*)iter->data)->crd.y][((wall_t*)iter->data)->crd.x] = WALL;
        iter = iter->next;
    }

    free_list(walls_list);
    
    for (tmp.x = 0; tmp.x < WIDTH_AREA; ++tmp.x)
    {
        for (tmp.y = 0; tmp.y < HEIGHT_AREA; ++tmp.y)
        {
            if (q_map[tmp.y][tmp.x] != 0x00) continue;

            q_map[tmp.y][tmp.x] = FOOD;
        }
    }

    while (1)
    {
        tmp.x = rand() % WIDTH_AREA;
        tmp.y = rand() % HEIGHT_AREA;

        if (q_map[tmp.y][tmp.x] != FOOD) continue;

        q_map[tmp.y][tmp.x] = PLAYER;
        return tmp;
    }
}


void gen_start_crd(crd_t f_pl, crd_t pl_crd[])
{
    pl_crd[0] = f_pl;
    fprintf(log_file, "[SERVER] Position 1 player x: %d y: %d\n", pl_crd[0].x, pl_crd[0].y);

    pl_crd[1].x = WIDTH_AREA*2 - 1 - f_pl.x;
    pl_crd[1].y = f_pl.y;
    fprintf(log_file, "[SERVER] Position 2 player x: %d y: %d\n", pl_crd[1].x, pl_crd[1].y);

    pl_crd[2].x = f_pl.x;
    pl_crd[2].y = HEIGHT_AREA*2 - 1 - f_pl.y;
    fprintf(log_file, "[SERVER] Position 3 player x: %d y: %d\n", pl_crd[2].x, pl_crd[2].y);

    pl_crd[3].x = WIDTH_AREA*2 - 1 - f_pl.x;
    pl_crd[3].y = HEIGHT_AREA*2 - 1 - f_pl.y;
    fprintf(log_file, "[SERVER] Position 4 player x: %d y: %d\n", pl_crd[3].x, pl_crd[3].y);
}
